<?php
require_once dirname(__FILE__) . '/EventPair.php';
require_once dirname(__FILE__) . '/BaseEvent.php';
require_once dirname(__FILE__) . '/VisitorEvent.php';
require_once dirname(__FILE__) . '/StaffEvent.php';
require_once dirname(__FILE__) . '/EventDAL.php';
require_once dirname(__FILE__) . '/../google/src/Google_Client.php';
require_once dirname(__FILE__) . '/../google/src/contrib/Google_CalendarService.php';

class EventModel {
	private $googleCalendarService;

  private static $timeZone = 'Europe/Stockholm';
  private static $k_id = 'id';
	private static $k_items = 'items';
	private static $k_summary = 'summary';
	private static $k_description = 'description';
	private static $k_start = 'start';
	private static $k_end = 'end';
	private static $k_dateTime = 'dateTime';
  private static $k_private = 'private';
  private static $k_public = 'public';

  private static $dateFormat = 'Y-m-d\TH:i:s';

  private $dal = null;

  public function __construct(Database $db) {
    $this->dal = new EventDAL($db);
    $client = new Google_Client();
    $client->setApplicationName("Bokningssystem");
    $client->setClientId(Settings::G_CLIENT_ID);
    $keyFileName = dirname(__FILE__) . '/../../key/googleServiceAccountPrivateKey.p12';
    $key = file_get_contents($keyFileName);

    $client->setAssertionCredentials(new Google_AssertionCredentials(
      Settings::G_SERVICE_ACCOUNT,
      'https://www.google.com/calendar/feeds/' . Settings::G_CALENDAR_ID . '/private/full/',
      $key
    ));
    $client->setUseObjects(true);
    $this->googleCalendarService = new Google_CalendarService($client);
  }

  /**
  * Lägg eller uppdatera event i databas och Google Calendar
  *
  * @param EventPair
  */
  public function addEvent(EventPair $event) {
    $addedVisitorEvent = $this->addVisitorEvent($event->visitorEvent);
    $addedStaffEvent = $this->addStaffEvent($event->staffEvent, $event->visitorEvent->getId());

    $addedEvent = EventPair::create($addedVisitorEvent, $addedStaffEvent);

    // Om eventet har ett id från början blir dessa samma och det är en update
    if ($event->visitorEvent->getId() == $addedVisitorEvent->getId()) {
      $this->dal->updateEventMetaData($addedEvent);
    } else {
      $this->dal->addEventMetaData($addedEvent);
    }
  }

  /**
  * Radera event ur databas och Google Calendar
  *
  * @param String (google calendar event-id)
  */
  public function deleteEvent($visitorEventId) {
    $staffEventId = $this->getStaffEventId($visitorEventId);

    // TODO Kontrollera att de verkligen raderas.
    $this->googleCalendarService->events->delete(Settings::G_CALENDAR_ID, $visitorEventId);
    $this->googleCalendarService->events->delete(Settings::G_CALENDAR_ID, $staffEventId);

    $this->dal->deleteEventsMetaData($visitorEventId);
  }

  /**
  * Hämta information om event från databasen
  *
  * @param String (google calendar event-id)
  *
  * @return array EventPair
  */
  private function getEventsMetaDataFromDb($visitorEventId = null) {
    $events = $this->dal->getEventsMetaData($visitorEventId);
        
    return $events;
  }

  /**
  * @param String (google calendar event-id)
  *
  * @return String (google calendar event-id)
  */
  private function getStaffEventId($visitorEventId) {
    $eventPair = $this->getEventsMetaDataFromDb($visitorEventId);
    $eventPair = $eventPair[0];

    return $eventPair->staffEvent->getId();
  }

  /**
  * Hjälpfunktion för att lägga till besökarevent
  *
  * @param VisitorEvent
  *
  * @return VisitorEvent
  */
  private function addVisitorEvent(VisitorEvent $visitorEvent) {
    $event = new Google_Event();
    $event->setSummary($visitorEvent->getTitle());
    //$event->setLocation('Studentpuben');
    $event->setDescription($visitorEvent->getDescription());
    $event->setVisibility(self::$k_public);

    $start = $this->getGoogleEventTime($visitorEvent->getStartDateTime());
    $event->setStart($start);

    $end = $this->getGoogleEventTime($visitorEvent->getEndDateTime());
    $event->setEnd($end);

    if ($visitorEvent->getId()) {
      $gEvent = $this->googleCalendarService->events->update(Settings::G_CALENDAR_ID, $visitorEvent->getId(), $event);
    } else {
      $gEvent = $this->googleCalendarService->events->insert(Settings::G_CALENDAR_ID, $event);
    }
    return $this->getVisitorEvent($gEvent);
  }

  /**
  * Hjälpfunktion för att lägga till jobbarevent
  *
  * @param StaffEvent
  * @param String (google calendar event-id)
  *
  * @return StaffEvent
  */
  private function addStaffEvent(StaffEvent $staffEvent, $visitorEventId) {
    $event = new Google_Event();
    $event->setSummary($staffEvent->getTitle());
    $event->setDescription($staffEvent->getDescription());
    $event->setVisibility(self::$k_private);

    $start = $this->getGoogleEventTime($staffEvent->getStartDateTime());
    $event->setStart($start);

    $end = $this->getGoogleEventTime($staffEvent->getEndDateTime());
    $event->setEnd($end);

    if ($staffEvent->getId()) {
      $gEvent = $this->googleCalendarService->events->update(Settings::G_CALENDAR_ID, $staffEvent->getId(), $event);
    } else {
      $gEvent = $this->googleCalendarService->events->insert(Settings::G_CALENDAR_ID, $event);
    }
    return $this->getStaffEvent($gEvent);
  }

  /**
  * @param String (tid- och datumsträng)
  *
  * @return Google_EventDateTime
  */
  private function getGoogleEventTime($time) {
    $dateTime = new Google_EventDateTime();
    $dateTime->setDateTime($time);
    $dateTime->setTimeZone(self::$timeZone);
    return $dateTime;
  }

  /**
  * Skapar ett jobbarevent utifråån ett google-event
  *
  * @param Google_Event
  *
  * @return StaffEvent
  */
  private function getStaffEvent(Google_Event $gEvent) {
    $id = $gEvent->getId();
    $title = $gEvent->getSummary();
    $description = $gEvent->getDescription();
    $startTime = $gEvent->getStart()->getDateTime();
    $endTime = $gEvent->getEnd()->getDateTime();

    // Ta bort information om tidszon
    $startTime = substr($startTime, 0, 19);
    $endTime = substr($endTime, 0, 19);

    $staffEvent = StaffEvent::create($id, $title, $description, $startTime, $endTime, $attendees = null);

    return $staffEvent;
  }

  /**
  * Skapar ett besökarevent utifråån ett google-event
  *
  * @param Google_Event
  *
  * @return StaffEvent
  */
  private function getVisitorEvent(Google_Event $gEvent) {
    $id = $gEvent->getId();
    $title = $gEvent->getSummary();
    $description = $gEvent->getDescription();
    $startTime = $gEvent->getStart()->getDateTime();
    $endTime = $gEvent->getEnd()->getDateTime();

    // Ta bort information om tidszon
    $startTime = substr($startTime, 0, 19);
    $endTime = substr($endTime, 0, 19);

    $visitorEvent = VisitorEvent::create($id, $title, $description, $startTime, $endTime);

    return $visitorEvent;
  }

  /**
  * @param String (google calendar event-id)
  *
  * @return EventPair
  */
  public function getEvent($visitorEventId) {
    $eventPair = null;

    $staffEventId = $this->getStaffEventId($visitorEventId);

    if ($staffEventId) {
      $gVEvent = $this->googleCalendarService->events->get(Settings::G_CALENDAR_ID, $visitorEventId);
      $gSEvent = $this->googleCalendarService->events->get(Settings::G_CALENDAR_ID, $staffEventId);

      $visitorEvent = $this->getVisitorEvent($gVEvent);
      $staffEvent = $this->getStaffEvent($gSEvent);

      $eventPair = EventPair::create($visitorEvent, $staffEvent);
    }

    return $eventPair;
  }

  /**
  * @return array EventPair
  */
  public function getEvents() {
    date_default_timezone_set('Europe/Stockholm');
    $currTime = date('Y-m-d\TH:i:sP', time());

    $eventsArray = $this->googleCalendarService->events->listEvents(Settings::G_CALENDAR_ID, array(
                                                                                            'singleEvents'  => true,
                                                                                            'orderBy' => 'startTime',                                                                                
                                                                                        ));
    $eventsArray = $eventsArray->getItems();

    $staffEvents = array();
    $visitorEvents = array();
    $eventPairs = array();

    $metaEventPairs = $this->getEventsMetaDataFromDb();

    if (count($eventsArray) > 0) {
      foreach ($eventsArray as $gEvent) {      
        if ($gEvent->getVisibility() == self::$k_private) {
          $staffEvents[] = $this->getStaffEvent($gEvent);
        } else {
          $visitorEvents[] = $this->getVisitorEvent($gEvent);
        }      
      } 

      $length = count($metaEventPairs);
      $metaEvent = null;
      $visitorEvent = null;
      $staffEvent = null;

      for ($i = 0; $i < $length; $i += 1) {
        $metaEvent = $metaEventPairs[$i];
        $visitorEvent = null;
        $staffEvent = null;

        if (count($metaEventPairs) <= count($visitorEvents) && count($metaEventPairs) <= count($staffEvents)) {
          $visitorEvent = $visitorEvents[$i];
          $staffEvent = $staffEvents[$i];
        } else {
          // Detta sker bara ifall databas och googlekalender inte stämmer överens
          // Här lägger vi till godtyckliga event för att kunna fortsätta
          // TODO lägg till information om detta i logg
          $visitorEvent = $visitorEvents[0];
          $staffEvent = $staffEvents[0];
        }

        if ($metaEvent->visitorEvent->getId() !=  $visitorEvent->getId()) {
          // Hit borde vi bara komma om databasen inte stämmer överens med googlekalendern
          $visitorEvent = null;

          $vELength = count($visitorEvents);

          for ($j = 0; $j < $vELength; $j += 1) {
            if ($metaEvent->visitorEvent->getId() ==  $visitorEvents[$j]->getId()) {
              $visitorEvent = $visitorEvents[$j];
            }
          }  
        }

        if ($metaEvent->staffEvent->getId() !=  $staffEvent->getId()) {
          // Hit borde vi bara komma om databasen inte stämmer överens med googlekalendern
          $staffEvent = null;

          // Sök igenom alla om det inte finns där vi förväntar oss
          $sELength = count($staffEvents);
          for ($k = 0; $k < $sELength; $k += 1) {
            if ($metaEvent->staffEvent->getId() ==  $staffEvents[$k]->getId()) {
              $staffEvent = $staffEvents[$k];
            }
          }     
        }
        // Om eventet finns idatabasen men inte i googlekalendern ignoreras det
        if ($visitorEvent != null && $staffEvent != null) {
          $eventPairs[] = EventPair::create($visitorEvent, $staffEvent);
        }
      }
    }

    return $eventPairs;
  }
}